package main

import (
	"fmt"
	"sync"
)

//引入WaitGroup，类似于java中的countDownLatch
var wg sync.WaitGroup

func main() {

	//demo01SimpleWg()

	demo02WgWithDefer()

}

func demo01SimpleWg() {
	for i := 0; i < 10; i++ {
		wg.Add(1) // 启动一个goroutine就登记+1
		go hello(i)
	}
	wg.Wait() // 等待所有登记的goroutine都结束
	fmt.Println("主协程结束")
}

func hello(i int) {
	fmt.Println("Hello Goroutine!", i)
	wg.Done() // wg 登记-1

}

/*
defer可以使得就算协程报错，也可以不影响主协程的运行
*/
func demo02WgWithDefer() {
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go hello2(i)
	}
	wg.Wait()
	fmt.Println("主协程结束")
}

/*
Hello2 Goroutine! 4
Hello2 Goroutine! 1
Hello2 Goroutine! 0
Hello2 Goroutine! 6
Hello2 Goroutine! 5
Hello2 Goroutine! 2
Hello2 Goroutine! 7
Hello2 Goroutine! 8
routine 9 throws exception!! recovered!!
routine 3 throws exception!! recovered!!
主协程结束
*/
func hello2(i int) {
	defer func(i int) {

		// 如果协程报错，就recover，让程序不终止
		if err := recover(); err != nil {
			fmt.Printf("routine %d throws exception!! recovered!!\n", i)
		}
		wg.Done()
	}(i)

	// 模拟协程报错
	if i == 3 || i == 9 {
		panic("error!!!!!")
	}
	fmt.Println("Hello2 Goroutine!", i)
}
